/*
 * Copyright (C) 2017 zhouyou(478319399@qq.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.shuyihui.rxhttp.subsciber

import android.content.Context
import android.text.TextUtils
import com.shuyihui.rxhttp.callback.CallBack
import com.shuyihui.rxhttp.callback.DownloadProgressCallBack
import com.shuyihui.rxhttp.exception.ApiException
import com.shuyihui.rxhttp.utils.HttpLog
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import okhttp3.ResponseBody
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream

/**
 *
 * 描述：定义一个下载的订阅者
 */
class DownloadSubscriber<responseBody : ResponseBody?>(
    private val context: Context,
    private val path: String,
    private val name: String,
    var mCallBack: CallBack<*>?
) : BaseSubscriber<ResponseBody>(
    context
) {
    private var lastRefreshUiTime: Long
    public override fun onStart() {
        super.onStart()
        mCallBack?.apply {
            this.onStart()
        }
        /*if (mCallBack != null) {
            mCallBack!!.onStart()
        }*/
    }

    override fun onComplete() {
        mCallBack?.run {
            onCompleted()
        }
         /*if (mCallBack != null) {
            mCallBack!!.onCompleted();
        }*/
    }

    override fun onError(e: ApiException) {
        HttpLog.d("DownSubscriber:>>>> onError:" + e.message)
        finalonError(e)
    }


    override fun onNext(responseBody: ResponseBody) {
        HttpLog.d("DownSubscriber:>>>> onNext")
        writeResponseBodyToDisk(path, name, context, responseBody)
    }

    private fun writeResponseBodyToDisk(
        path: String,
        name: String,
        context: Context,
        body: ResponseBody
    ): Boolean {
        //HttpLog.d("contentType:>>>>" + body.contentType().toString());
        var path: String? = path
        var name = name
        if (!TextUtils.isEmpty(name)) { //text/html; charset=utf-8
            val type: String
            if (!name.contains(".")) {
                type = body!!.contentType().toString()
                if ((type == APK_CONTENTTYPE)) {
                    fileSuffix = ".apk"
                } else if ((type == PNG_CONTENTTYPE)) {
                    fileSuffix = ".png"
                } else if ((type == JPG_CONTENTTYPE)) {
                    fileSuffix = ".jpg"
                } else {
                    fileSuffix = "." + body!!.contentType()!!.subtype
                }
                name += fileSuffix
            }
        } else {
            name = System.currentTimeMillis().toString() + fileSuffix
        }
        if (path == null) {
            path = context.getExternalFilesDir(null).toString() + File.separator + name
        } else {
            val file = File(path)
            if (!file.exists()) {
                file.mkdirs()
            }
            path = path + File.separator + name
            path = path.replace("//".toRegex(), "/")
        }
        HttpLog.i("path:-->$path")
        try {
            val futureStudioIconFile = File(path)
            /* if (!futureStudioIconFile.exists()) {
                futureStudioIconFile.createNewFile();
            }*/
            var inputStream: InputStream? = null
            var outputStream: FileOutputStream? = null
            try {
                //byte[] fileReader = new byte[2048];
                val fileReader = ByteArray(1024 * 128)
                val fileSize = body!!.contentLength()
                var fileSizeDownloaded: Long = 0
                HttpLog.d("file length: $fileSize")
                inputStream = body!!.byteStream()
                outputStream = FileOutputStream(futureStudioIconFile)
                val callBack = mCallBack
                while (true) {
                    val read = inputStream.read(fileReader)
                    if (read == -1) {
                        break
                    }
                    outputStream.write(fileReader, 0, read)
                    fileSizeDownloaded += read.toLong()
                    HttpLog.i("file download: $fileSizeDownloaded of $fileSize")
                    //下载进度
                    val progress = fileSizeDownloaded * 1.0f / fileSize
                    val curTime = System.currentTimeMillis()
                    //每200毫秒刷新一次数据,防止频繁更新进度
                    if (curTime - lastRefreshUiTime >= 200 || progress == 1.0f) {
                        if (callBack != null) {
                            val finalFileSizeDownloaded = fileSizeDownloaded
                            Observable.just(finalFileSizeDownloaded)
                                .observeOn(AndroidSchedulers.mainThread())
                                .subscribe({
                                    if (callBack is DownloadProgressCallBack<*>) {
                                        callBack.update(
                                            finalFileSizeDownloaded,
                                            fileSize,
                                            finalFileSizeDownloaded == fileSize
                                        )
                                    }
                                }) { }
                        }
                        lastRefreshUiTime = System.currentTimeMillis()
                    }
                }
                outputStream.flush()
                HttpLog.i("file downloaded: $fileSizeDownloaded of $fileSize")
                if (callBack != null) {
                    //final String finalName = name;
                    val finalPath: String = path
                    Observable.just(finalPath).observeOn(AndroidSchedulers.mainThread()).subscribe(
                        {
                            if (callBack is DownloadProgressCallBack<*>) {
                                callBack.onComplete(finalPath)
                            }
                        }) { }
                    HttpLog.i("file downloaded: $fileSizeDownloaded of $fileSize")
                    HttpLog.i("file downloaded: is sucess")
                }
                return true
            } catch (e: IOException) {
                finalonError(e)
                return false
            } finally {
                outputStream?.close()
                inputStream?.close()
            }
        } catch (e: IOException) {
            finalonError(e)
            return false
        }
    }

    private fun finalonError(e: Exception) {
        if (mCallBack == null) {
            return
        }
        //if (Utils.checkMain()) {
        Observable.just(ApiException(e, 100)).observeOn(AndroidSchedulers.mainThread()).subscribe(
            { e ->
                mCallBack?.run {
                    onError(e)
                }
                /*if (mCallBack != null) {
                    mCallBack!!.onError(e)
                }*/
            }, object : Consumer<Throwable> {
                @Throws(Exception::class)
                override fun accept(throwable: Throwable) {
                }
            })
    }

    companion object {
        private val APK_CONTENTTYPE = "application/vnd.android.package-archive"
        private val PNG_CONTENTTYPE = "image/png"
        private val JPG_CONTENTTYPE = "image/jpg"

        //private static String TEXT_CONTENTTYPE = "text/html; charset=utf-8";
        private var fileSuffix = ""
    }

    init {
        lastRefreshUiTime = System.currentTimeMillis()
    }
}